﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Sunny.Entity;
using Sunny.Model.RequestParam;
using Sunny.Model.Vo;
using Sunny.Util.Exception;

namespace Sunny.Service
{
    public class RoleService
    {
        private readonly SunnyContext _sunnyContext;

        public RoleService(SunnyContext sunnyContext)
        {
            _sunnyContext = sunnyContext;
        }
        
        public async Task<List<long>> GetRoleIdsByUserId(long userId)
        {
            var roleIds = await _sunnyContext.SysUserRoles.Where(t=>t.UserId == userId).Select(t=>t.RoleId).ToListAsync();
            return roleIds;
        }
        public async Task<string> GetRoleNamesByUserId(long userId)
        {
            var roleIds = _sunnyContext.SysUserRoles.Where(t=>t.UserId == userId).Select(t=>t.RoleId);
            var listRole = await _sunnyContext.SysRoles.Where(t=>roleIds.Contains(t.RoleId)).Select(t=>t.RoleName).ToListAsync();
            return string.Join("/",listRole);
        }

        public async Task<List<SysRole>> GetAll()
        {
            return await _sunnyContext.SysRoles.ToListAsync();
        }

        public async Task<(List<SysRole>, int)> List(RoleListParam param)
        {
            var roles = _sunnyContext.SysRoles.AsQueryable();
            if(!string.IsNullOrEmpty(param.RoleName))
            {
                roles = roles.Where(t=>t.RoleName.Contains(param.RoleName));
            }
            if(!string.IsNullOrEmpty(param.RoleKey))
            {
                roles = roles.Where(t=>t.RoleKey.Contains(param.RoleKey));
            }
            if(!string.IsNullOrEmpty(param.Status))
            {
                roles = roles.Where(t=>t.Status == param.Status);
            }
            int total = await roles.CountAsync();
            var roleList= await roles.Skip((param.PageNum-1)*param.PageSize).Take(param.PageSize).ToListAsync();
            return (roleList,total);
        }

        public async Task ChangeStatus(RoleChangeStatusParam param)
        {
            var role = await _sunnyContext.SysRoles.SingleOrDefaultAsync(t=>t.RoleId == param.RoleId);
            role.Status = param.Status;
            await _sunnyContext.SaveChangesAsync();
        }

        public async Task Add(RoleAddParam param)
        {
            await _sunnyContext.Database.BeginTransactionAsync();
            SysRole sysRole = new SysRole();
            sysRole.DeptCheckStrictly = param.DeptCheckStrictly?(byte)1:(byte)0;
            sysRole.MenuCheckStrictly = param.MenuCheckStrictly?(byte)1:(byte)0;
            sysRole.Remark = param.Remark;
            sysRole.RoleKey = param.RoleKey;
            sysRole.RoleName = param.RoleName;
            sysRole.RoleSort = param.RoleSort;
            sysRole.Status = param.Status;
            
            await _sunnyContext.SysRoles.AddAsync(sysRole);
            await _sunnyContext.SaveChangesAsync();

            foreach (var menuId in param.MenuIds)
            {
                SysRoleMenu sysRoleMenu = new SysRoleMenu()
                {
                    RoleId =  sysRole.RoleId,
                    MenuId =  menuId
                };
                await _sunnyContext.SysRoleMenus.AddAsync(sysRoleMenu);
            }
         
            await _sunnyContext.SaveChangesAsync();
            await _sunnyContext.Database.CommitTransactionAsync();
        }

        public async Task<SysRole> GetById(long roleId)
        {
            return await _sunnyContext.SysRoles.SingleOrDefaultAsync(t=>t.RoleId == roleId);
        }

        public async Task Update(RoleEditParam param)
        {
            SysRole sysRole = await _sunnyContext.SysRoles.SingleOrDefaultAsync(t=>t.RoleId == param.RoleId);
            if(sysRole == null)
            {
                throw new BusinessException(CodeMessage.RoleNotExists);
            }
            sysRole.DeptCheckStrictly = param.DeptCheckStrictly?(byte)1:(byte)0;
            sysRole.MenuCheckStrictly = param.MenuCheckStrictly?(byte)1:(byte)0;
            sysRole.Remark = param.Remark;
            sysRole.RoleKey = param.RoleKey;
            sysRole.RoleName = param.RoleName;
            sysRole.RoleSort = param.RoleSort;
            sysRole.Status = param.Status;

            var sysRoleMenus = _sunnyContext.SysRoleMenus.Where(t=>t.RoleId == param.RoleId);
            _sunnyContext.RemoveRange(sysRoleMenus);


            foreach (var menuId in param.MenuIds)
            {
                SysRoleMenu sysRoleMenu = new SysRoleMenu()
                {
                    RoleId =  sysRole.RoleId,
                    MenuId =  menuId
                };
                await _sunnyContext.SysRoleMenus.AddAsync(sysRoleMenu);
            }
         
            await _sunnyContext.SaveChangesAsync();
        }

        public async Task Delete(long roleId)
        {
            var role = await _sunnyContext.SysRoles.SingleOrDefaultAsync(t=>t.RoleId == roleId);
            role.DelFlag = 1;
            await _sunnyContext.SaveChangesAsync();
        }

        public async Task ChangeDataScope(RoleDataScopeEditParam param)
        {
            var role = await _sunnyContext.SysRoles.SingleOrDefaultAsync(t=>t.RoleId == param.RoleId);
            role.DataScope = param.DataScope;
            
            var roleDepts = _sunnyContext.SysRoleDepts.Where(t=>t.RoleId == param.RoleId);
            _sunnyContext.SysRoleDepts.RemoveRange(roleDepts);
            
            if(param.DeptIds != null)
            {
                foreach (var deptId in param.DeptIds)
                {
                    SysRoleDept sysRoleDept = new SysRoleDept(){ RoleId = param.RoleId,DeptId =  deptId};
                    await _sunnyContext.SysRoleDepts.AddAsync(sysRoleDept);
                }
            }
            await _sunnyContext.SaveChangesAsync();
        }

        public async Task<(List<SysUser>, int)> AuthUser(RoleAuthUserParam param)
        {
            var sysUserIds = _sunnyContext.SysUserRoles.Where(t=>t.RoleId == param.RoleId).Select(t=>t.UserId);
            var users = _sunnyContext.SysUsers.Where(t=>sysUserIds.Contains(t.UserId));
            if(!string.IsNullOrEmpty(param.UserName))
            {
                users = users.Where(t=>t.UserName.Contains(param.UserName));
            }
            if(!string.IsNullOrEmpty(param.Phonenumber))
            {
                users = users.Where(t=>t.Phonenumber.Contains(param.Phonenumber));
            }
            int total = await users.CountAsync();
            var userList  = await users.OrderBy(t=>t.UserId).Skip((param.PageNum-1)*param.PageSize).Take(param.PageSize).ToListAsync();
            return (userList,total);
        }

        public async Task<(List<SysUser>, int)> NoAuthUser(RoleAuthUserParam param)
        {
            var sysUserIds = _sunnyContext.SysUserRoles.Where(t=>t.RoleId == param.RoleId).Select(t=>t.UserId);
            var users = _sunnyContext.SysUsers.Where(t=> !sysUserIds.Contains(t.UserId));
            if(!string.IsNullOrEmpty(param.UserName))
            {
                users = users.Where(t=>t.UserName.Contains(param.UserName));
            }
            if(!string.IsNullOrEmpty(param.Phonenumber))
            {
                users = users.Where(t=>t.Phonenumber.Contains(param.Phonenumber));
            }
            int total = await users.CountAsync();
            var userList  = await users.OrderBy(t=>t.UserId).Skip((param.PageNum-1)*param.PageSize).Take(param.PageSize).ToListAsync();
            return (userList,total);
        }

        public async Task AuthUserAll(RoleAuthUserEditParam param)
        {
            var strUserIds = param.UserIds.Split(",");
            var userIds = Array.ConvertAll(strUserIds,long.Parse);
            foreach (var userId in userIds)
            {
                await _sunnyContext.SysUserRoles.AddAsync(new SysUserRole(){ RoleId = param.RoleId,UserId = userId});
            }
            await _sunnyContext.SaveChangesAsync();
        }

        public async Task UnAuthUserAll(RoleAuthUserEditParam param)
        {
            var strUserIds = param.UserIds.Split(",");
            var userIds = Array.ConvertAll(strUserIds,long.Parse);

            var sysUserRoles = _sunnyContext.SysUserRoles.Where(t=>t.RoleId == param.RoleId && userIds.Contains(t.UserId));
            _sunnyContext.SysUserRoles.RemoveRange(sysUserRoles);

            await _sunnyContext.SaveChangesAsync();
        }
    }
}